/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#ifndef M_FUNCTORS_H
#define M_FUNCTORS_H

namespace Engine
{
	/********************************* std::map ******************************************************************/

	template<class F>
	struct _on2nd
	{
		F _func;
		_on2nd(F _f): _func(_f){}

		template<class p>
		void operator()(p& x)
		{
			_func(x.second);
		}
	};

	template<class F> inline
	_on2nd<F> on2nd(F _f)
	{
		return _on2nd<F>(_f);
	}
	/********************************* RefPtr  ******************************************************************/

	template<class _Result, class _Ty>
	class sptr_mem_fun_t
	{	// functor (*p->*pfunc)(), non-const *pfunc
	public:
		typedef _Result result_type;

		explicit sptr_mem_fun_t(_Result (_Ty::*_Pm)())
			: _Pmemfun(_Pm)
		{	// construct from pointer
		}

		template<class SPTR>
		_Result operator()(SPTR _Pleft) const
		{	// call function
			return ((_Pleft.GetPointer()->*_Pmemfun)());
		}

	private:
		_Result (_Ty::*_Pmemfun)();	// the member function pointer
	};

	template<class _Result,	class _Ty>
	class sptr_const_mem_fun_t
	{	// functor (*p->*pfunc)(), const *pfunc
	public:
		typedef _Result result_type;

		explicit sptr_const_mem_fun_t(_Result (_Ty::*_Pm)() const)
			: _Pmemfun(_Pm)
		{	// construct from pointer
		}

		template<class SPTR>
		_Result operator()(SPTR _Pleft) const
		{	// call function
			return ((_Pleft.GetPointer()->*_Pmemfun)());
		}

	private:
		_Result (_Ty::*_Pmemfun)() const;	// the member function pointer
	};


	template<class _Result, class _Ty, class _Arg>
	class sptr_mem_fun1_t
	{	// functor (*p->*pfunc)(val), non-const *pfunc
	public:
		typedef _Result result_type;

		explicit sptr_mem_fun1_t(_Result (_Ty::*_Pm)(_Arg))
			: _Pmemfun(_Pm)
		{	// construct from pointer
		}

		template<class SPTR>
		_Result operator()(SPTR _Pleft, _Arg _Right) const
		{	// call function with operand
			return ((_Pleft.GetPointer()->*_Pmemfun)(_Right));
		}

	private:
		_Result (_Ty::*_Pmemfun)(_Arg);	// the member function pointer
	};

	template<class _Result, class _Ty, class _Arg>
	class sptr_const_mem_fun1_t
	{	// functor  (*p->*pfunc)(val), const *pfunc
	public:
		typedef _Result result_type;

		explicit sptr_const_mem_fun1_t(_Result (_Ty::*_Pm)(_Arg) const)
			: _Pmemfun(_Pm)
		{	// construct from pointer
		}

		template<class SPTR>
		_Result operator()(const SPTR _Pleft, _Arg _Right) const
		{	// call function with operand
			return ((_Pleft.GetPointer()->*_Pmemfun)(_Right));
		}

	private:
		_Result (_Ty::*_Pmemfun)(_Arg) const;	// the member function pointer
	};

	template<class _Result,class _Ty> inline
	sptr_mem_fun_t<_Result, _Ty>
	m_fn(_Result (_Ty::*_Pm)())
	{
		return (sptr_mem_fun_t<_Result, _Ty>(_Pm));
	}

	template<class _Result,class _Ty> inline
	sptr_const_mem_fun_t<_Result, _Ty>
	m_fn(_Result (_Ty::*_Pm)() const)
	{
		return (sptr_const_mem_fun_t<_Result, _Ty>(_Pm));
	}

	template<class _Result, class _Ty,class _Arg> inline
	sptr_mem_fun1_t<_Result, _Ty, _Arg>
	m_fn(_Result (_Ty::*_Pm)(_Arg))
	{
		return (sptr_mem_fun1_t<_Result, _Ty, _Arg>(_Pm));
	}

	template<class _Result, class _Ty, class _Arg> inline
	sptr_const_mem_fun1_t<_Result, _Ty, _Arg>
	m_fn(_Result (_Ty::*_Pm)(_Arg) const)
	{
		return (sptr_const_mem_fun1_t<_Result, _Ty, _Arg>(_Pm));
	}

	/******************************************************************************************************/
	template<class _Fn2, class _Arg>
	class _b2nd
	{
	public:
		_b2nd(const _Fn2& _Func,_Arg _Right)
			: op(_Func), value(_Right)
		{	// construct from functor and right operand
		}

		template<class _T>
		typename _Fn2::result_type operator()(_T& _Left) const
		{	// apply functor to operands
			return (op(_Left, value));
		}

		protected:
		_Fn2 op;	// the functor to apply
		_Arg value;	// the right operand
	};

	template<class _Fn2,class _Ty> inline
	_b2nd<_Fn2, _Ty> b2nd(const _Fn2& _Func, const _Ty& _Right)
	{
		return (_b2nd<_Fn2,_Ty>(_Func, _Right));
	}
}

#endif
